if(!dojo._hasResource["dojox.widget.SearchSortList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.widget.SearchSortList"] = true;
dojo.provide("dojox.widget.SearchSortList");
dojo.experimental("dojox.widget.SearchSortList"); // level: prototype, designed for dijit.chat.demo

dojo.require("dijit.layout._LayoutWidget");
dojo.require("dijit._Templated");
dojo.require("dojo.dnd.Source"); 
dojo.require("dijit.Tooltip");

dojo.declare("dojox.widget.SearchSortList",
	[dijit.layout._LayoutWidget, dijit._Templated],
	{
	// summary: A sortable unordered-list with a fixed header for use in dijit.demos.chat
	//		for demonstration purposes only for now. feel free to make API suggestions
	//		or fixes. 
	//
	// title: String 
	//		The title in the header
	title: "",
	
	// heading: String
	//		In the event a parent container is expecting a title="" attribute, set it for the parent 
	//		via title, and the title of this widget via heading="" ... assuming you want different 
	//		titles for each. eg: TabContainer, AccordionContainer, etc. 
	heading: "",

	// descending: Boolean
	//		Toggle sort order based on this value. 
	descending: true,

	// selected: Array
	//		A list of the selected <li> nodes at any given time.
	selected: null,

	// sortable: Boolean
	//	toggle to enable/disable sorting
	sortable: true,
	
	source: null, 
	
	multiselect: false, 

	// FIXME: this is really simple store support
	store: "",
	key: "Title",

	templateString:"<div class=\"sortList\" id=\"${id}\">\n\t\t<div class=\"sortListTitle\" dojoAttachPoint=\"titleNode\">\n\t\t<div class=\"sortListIcon\"></div>\n\t\t<span dojoAttachPoint=\"focusNode\">${title}</span>\n\t\t</div>\n\t\t<div class=\"sortListBodyWrapper\" dojoAttachEvent=\"onmouseover: _set, onmouseout: _unset, onclick:_handleClick\" dojoAttachPoint=\"bodyWrapper\">\n\t\t<ul dojoAttachPoint=\"containerNode\" class=\"sortListBody\"></ul>\n\t</div>\n</div>\n",
	
	setDataStore: function(store, req) {
		// start from scratch
		//this.source.clearItems();
		this.containerNode.innerHTML = ""; 
		
		// add event notification to our datastore while retrieving query
		req.onItem = dojo.hitch(this, "_addItem");
		req.onComplete = dojo.hitch(this, "_onComplete", store, req); 
		
		// execute the query and store the request
		store.fetch(req);
		this.store = store;
		this.req = req; 
	}, 
	
	
	_onComplete: function(store, req) {
		
		// make the next and prev links
		var nextNode = dojo.doc.createElement('li');
		nextNode.innerHTML = "Next 20 ->";
		var nextreq = {};
		nextreq = this._cloneObject(req);
		nextreq.query.startindex = parseInt(req.query.startindex) + 20;
		
		dojo.connect(nextNode, "ondblclick", dojo.hitch(this, "setDataStore", this.store, nextreq));
		
		// create a new item hash to pass it to the creator
		var item = {};
		item.type = 'link'; 
		item.node = nextNode;
		
		this.source.insertNodes(false, [item]);
		
		if (parseInt(req.query.startindex) > 1) {
			var prevNode = dojo.doc.createElement('li');
			prevNode.innerHTML = "Prev 20 <-";
			prevreq = this._cloneObject(req);
			prevreq.query.startindex = parseInt(this.req.query.startindex) - 20;
			dojo.connect(prevNode, "ondblclick", dojo.hitch(this, "setDataStore", this.store, prevreq));
			
			var item={};
			item.type='link';
			item.node = prevNode;
			
			this.source.insertNodes(false, [item]);
		}
		
		this.reColor();
	}, 
	
	_addItem: function(item){
		var newNode = this.source.insertNodes(false, [item]);
	},

	postCreate: function(){
		if(this.store){
			this.store = dojo.getObject(this.store);
			var props = {
				onItem: dojo.hitch(this,"_addItem"),
				onComplete: dojo.hitch(this,"onSort")
			};
			this.store.fetch(props);	
		}else{ this.onSort(); }
		this.inherited(arguments);
		
	},

	startup: function(){		
		this.inherited(arguments);
		if(this.heading){ 
			this.setTitle(this.heading); this.title=this.heading; 
		}
		// we cheat, and give the browser just enough time so we know our height
		setTimeout(dojo.hitch(this,"resize"),5);
		if (this.sortable){ this.connect(this.titleNode,"onclick", "onSort"); }
		
		var self = this; 
		
		var displayVideo = function(video_id) {
			// make the embedded video object
			var embeddedNode = dojo.doc.createElement('embed');
			embeddedNode.setAttribute('src', 'http://www.youtube.com/v/'+video_id+'&autoplay=1');
			embeddedNode.setAttribute('type', 'application/x-shockwave-flash');
			embeddedNode.setAttribute('wmode', 'transparent');
			embeddedNode.setAttribute('width', '425');
			embeddedNode.setAttribute('height', '355');
			
			// clear the videoContent pane and add the new object
			dojo.byId('videoContent').innerHTML = "";
			dojo.byId('videoContent').appendChild(embeddedNode);
		}
		
		// make the SortList dnd
		var node_creator = function(item, hint){
			
			// is a youtube next, prev link, the node has already been processed
			if (item.type == 'link') {
				var types = ["song"];
				
				return {node: item.node, data: item.node, types: types}; 
			}
			// inserted from youtubestore, make a new node based off the store information
			else if (item.song == undefined) {
				
				var types = ["song"];
				
				var data = {};
				data.song = self.store.getValue(item, "title");
				data.artist = "";
				
				// create a new node and set its text 
				var node = dojo.doc.createElement("li");
				var text=data.song; 
				node.innerHTML="<span class='dojoDndHandle'>"+text+"</span>"; 
				
				
				// make a new tooltip connected to the node
				var description = self.store.getValue(item, "description").substring(0,100); 
				var thumbnail = self.store.getValue(item, "thumbnail");
				var tiphtml = "<div style='width: 150px; border: 1px; '><img src='"+thumbnail+"'><br/>"+description+'</div>';
				var tt = new dijit.Tooltip({label:tiphtml, connectNodes:[node]});
				
				data.video_id = self.store.getValue(item, "youtube_id");
				data.description = description;
				data.thumbnail = thumbnail; 
				
				dojo.connect(node, "ondblclick", dojo.hitch(null, displayVideo, data.video_id));
				
				var tt = new dijit.Tooltip({label:tiphtml, connectNodes:[node]});
				
				return {node: node, data: data, type: types};
			} else {
				var types = ["song"];
				
				var node = dojo.doc.createElement("div");
				node.setAttribute("style", "width: 100%;"); 
				node.className = "dojoDndItem";
				var text=item.song + " - " + item.artist; 
				node.innerHTML = text;
				node.id = dojo.dnd.getUniqueId();
			
				return {node: node, data: item, type: types};
			}
		};
				
		this.source = new dojo.dnd.Source(this.containerNode, {creator: node_creator, accept:["song"], withHandles: true} );
		
		var this_widget = this;
		dojo.subscribe("/dnd/drop", function(src, nodes, copy, target){	
				if(target = this_widget.source){
					this_widget.reColor();
				}
			});
	},
	
	resize: function(){
		// summary: do our additional calculations when resize() is called by or in a parent
		this.inherited(arguments);
		// FIXME: 
		// the 10 comes from the difference between the contentBox and calculated height
		// because of badding and border extents. this shouldn't be done this way, a theme change will 
		// break it: but we also don't want to run getComputedStyle or dojo.coords() every time resize() 
		// is fired.
		var offset = ((this._contentBox.h) - (dojo.style(this.titleNode,"height")))-30;
		this.bodyWrapper.style.height = Math.abs(offset) + "px"; 
	},
	
	onSort: function(/* Event */e){
		// summary: sort the data, and style the nodes.

		var arr = dojo.query("li",this.domNode);
		if (this.sortable){
			this.descending = !this.descending;
			dojo.addClass(this.titleNode,((this.descending)?"sortListDesc":"sortListAsc"));
			dojo.removeClass(this.titleNode,((this.descending)?"sortListAsc":"sortListDesc"));
			arr.sort(this._sorter);
			if(this.descending){ arr.reverse(); }
		}
		var i=0;
		dojo.forEach(arr,function(item){
			dojo[(i++)%2 === 0 ? "addClass" : "removeClass"](item,"sortListItemOdd");
			this.containerNode.appendChild(item); 
		},this);
	}, 
	
	reColor: function() {
		var arr = dojo.query("li", this.domNode);
		
		var i=0;
		dojo.forEach(arr,function(item){
			dojo[(i++)%2 === 0 ? "addClass" : "removeClass"](item,"sortListItemOdd");
			this.containerNode.appendChild(item); 
		},this);
	},
	
	resetHover: function(node) {
		var arr = dojo.query("li", this.domNode);
		
		var i=0;
		dojo.forEach(arr,function(item){
			if  (item != node) {
				dojo.removeClass(item, "sortListItemHover");
			}
		},this);
	},
	
	_set: function(/* Event */e){
		// summary: set hover state 
		/*
		if(e.target !== this.bodyWrapper){
			
			var target = e.target;
			
			if (e.target.tagName == 'SPAN') {
				target = e.target.parentNode; 
			}
			
			dojo.addClass(target,"sortListItemHover");
			this.current = target; 
		}*/
		
		//this.resetHover(e.target);
	},

	_unset: function(/* Event */e){
		// summary: remove hover state (FIXME: combine with _set?) 
		/*
		if(e.target !== this.bodyWrapper){
			
			var target = e.target;
			
			if (e.target.tagName == 'SPAN') {
				target = e.target.parentNode; 
			}
			
			dojo.removeClass(target,"sortListItemHover"); 
			this.current = target; 
		}*/
		
	},

	_handleClick: function(/* Event */e){
		// summary: click listener for data portion of widget. toggle selected state
		//	of node, and update this.selected array accordingly
		
		// first if this is not multiselect, remove all selected
		if (this.multiselect == false) {
			var arr = dojo.query("li", this.domNode);
			dojo.forEach(arr, function(item){
				dojo.removeClass(item, "sortListItemSelected");
			}, this);
		}
		
		var target = e.target;
			
		if (e.target.tagName == 'SPAN') {
				target = e.target.parentNode; 
		}
		
		if (target.tagName == 'LI') {
			dojo.toggleClass(target,"sortListItemSelected");
			e.target.focus();
			this._updateValues(e.target.innerHTML);
		}
	},

	_updateValues: function(){
		this._selected = dojo.query("li.sortListItemSelected",this.containerNode);
		this.selected = [];
		dojo.forEach(this._selected,function(node){
			this.selected.push(node.innerHTML);
		},this);
		this.onChanged(arguments);
	},

	_sorter: function(a,b){
		// summary: a basic sort function, use query sort, or keep this?
		var aStr = a.innerHTML;
		var bStr = b.innerHTML;
		if(aStr>bStr){ return 1; }
		if(aStr<bStr){ return -1; }
		return 0;
	},

	setTitle: function(/* String */title){
		// summary: Sets the widget title to a String
		this.focusNode.innerHTML = this.title = title;
	},

	onChanged: function(){
		// summary: stub function, passes the last changed item, and is fired after current state 
	},
	
	_cloneObject: function(object) {							 
		var newObj = {};
		newObj.query = {};
		newObj.query.vq = object.query.vq;
		newObj.query.startindex = object.query.startindex;
		newObj.query.maxresults = object.query.maxresults;
		
		return newObj; 
	}

});

}
